package com.airplane.hotdiscuss.network;

import com.airplane.hotdiscuss.util.MyLogger;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.AbstractHttpEntity;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

public class MyHttpTask implements Runnable {
    private final MyLogger logger = MyLogger.getLogger(MyHttpTask.class.getSimpleName());
    private final int NETWORK_ACCESS_TIMEOUT = 30000;

    private MyHttpRequest mRequest;
    private IHttpTaskListener mTaskListener;
    private boolean mIsCanceled = false;
    private boolean mIsTimeOut = false;
    private int mTransId = -1;
    private byte[] mResponseBody;

    public MyHttpTask(MyHttpRequest request, IHttpTaskListener listener) {
        mRequest = request;
        mTaskListener = listener;
    }

    public int getTransId() {
        return mTransId;
    }

    public void setTransId(int id) {
        mTransId = id;
    }

    public MyHttpRequest getRequest() {
        return mRequest;
    }

    public void setRequest(MyHttpRequest request) {
        mRequest = request;
    }

    public IHttpTaskListener getTaskListener() {
        return mTaskListener;
    }

    public void setTaskListener(IHttpTaskListener listener) {
        mTaskListener = listener;
    }

    public boolean isCanceled() {
        return mIsCanceled;
    }

    public void setIsCanceled(boolean isCanceled) {
        mIsCanceled = isCanceled;
    }

    public byte[] getResponseBody() {
        return mResponseBody;
    }

    @Override
    public void run() {
        logger.d("run() --> Enter");
        if (null == mRequest || null == mTaskListener) {
            logger.d("invalid request/listener, exit");
            return;
        }

        AbstractHttpClient client = getHttpClient();
        mTaskListener.taskStarted(this);

        // Whether network is ok or not.
        //if (TransportManagerImpl.getInstance()) {
            if (!doTask(client)) {
                logger.d("doTask failed!");
            }
        //}
        client.getConnectionManager().shutdown();

        if (null == mResponseBody) {
            mTaskListener.taskCompleted(this);
        } else {
            if (mIsCanceled)
                mTaskListener.taskCanceled(this);
            else
                mTaskListener.taskFailed(this);
        }
        logger.d("run() --> Exit");
    }

    private AbstractHttpClient getHttpClient() {
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, mRequest.getContentEncoding());
        HttpProtocolParams.setUseExpectContinue(params, false);
        HttpConnectionParams.setConnectionTimeout(params, NETWORK_ACCESS_TIMEOUT);
        HttpConnectionParams.setSoTimeout(params, NETWORK_ACCESS_TIMEOUT);

        AbstractHttpClient client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
                schemeRegistry), params);
        client.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(3, false));

        if (mRequest.getProxyHost() != null && mRequest.getProxyPort() > 0) {
            String proxyHost = mRequest.getProxyHost();
            int proxyPort = mRequest.getProxyPort();
            client.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY,
                    new HttpHost(proxyHost, proxyPort));
            logger.d("doTask(), set proxy: " + proxyHost + ":" + String.valueOf(proxyPort));
        }
        return client;
    }

    private boolean doTask(AbstractHttpClient client) {
        String url = mRequest.getUrlWithParams();
        logger.d("doTask(), url with params is: " + url);

        HttpUriRequest method = mRequest.isPostMethod() ? new HttpPost(url) : new HttpGet(url);
        HttpResponse response = null;

        if (mRequest.isPostMethod()) {
            try {
                AbstractHttpEntity entity = null;
                String requestBodyString = mRequest.getRequestBodyString();
                byte[] requestBody = mRequest.getRequestBody();
                if (requestBodyString != null) {
                    entity = new StringEntity(requestBodyString);
                    entity.setContentType(mRequest.getContentType());
                    entity.setContentEncoding(mRequest.getContentEncoding());
                } else if (requestBody != null) {
                    entity = new ByteArrayEntity(requestBody);
                    entity.setContentType(mRequest.getContentType());
                }
                ((HttpPost) method).setEntity(entity);
            } catch (UnsupportedEncodingException e) {
                logger.e("doTask(), http request error : " + e.getCause());
                return false;
            }
        }

        // Set header
        Map<String, String> headers = mRequest.getHeaders();
        if (headers != null && !headers.isEmpty()) {
            Iterator<Map.Entry<String, String>> iterator = headers.entrySet().iterator();
            while (iterator.hasNext()) {
                Entry<String, String> element = (Entry<String, String>) iterator.next();
                method.addHeader(element.getKey(), element.getValue());
            }
        }

        // Begin executing
        try {
            response = client.execute(method);
        } catch (ClientProtocolException e) {
            logger.e("Excute request error : ", e.getCause());
        } catch (IOException e) {
            logger.e("Excute request error1 : ", e.getCause());
        }

        // Check return code
        int statusCode = response.getStatusLine().getStatusCode();
        logger.d("http response code : " + statusCode);
        if (statusCode == HttpStatus.SC_OK) {
            return true;
        }

        HttpEntity entity = response.getEntity();
        try {
            mResponseBody = EntityUtils.toByteArray(entity);
            logger.d("doTask() get response:\n" + new String(mResponseBody));
        } catch (IOException e) {
            logger.e("doTask error : ", e.getCause());
        }

        return false;
    }
}
